package hotload

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"plugin"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
)

// PluginSymbol 表示插件符号
type PluginSymbol string

// PluginInfo 表示插件信息
type PluginInfo struct {
	// ID 是插件ID
	ID string
	// Name 是插件名称
	Name string
	// Version 是插件版本
	Version string
	// Path 是插件路径
	Path string
	// Symbols 是插件符号映射表
	Symbols map[PluginSymbol]interface{}
	// LoadTime 是加载时间
	LoadTime time.Time
	// Handle 是插件句柄
	Handle *plugin.Plugin
}

// PluginLoadEvent 表示插件加载事件
type PluginLoadEvent int

const (
	// PluginLoadEventLoaded 表示插件已加载事件
	PluginLoadEventLoaded PluginLoadEvent = iota
	// PluginLoadEventUnloaded 表示插件已卸载事件
	PluginLoadEventUnloaded
	// PluginLoadEventReloaded 表示插件已重新加载事件
	PluginLoadEventReloaded
	// PluginLoadEventFailed 表示插件加载失败事件
	PluginLoadEventFailed
)

// String 返回插件加载事件的字符串表示
func (e PluginLoadEvent) String() string {
	switch e {
	case PluginLoadEventLoaded:
		return "loaded"
	case PluginLoadEventUnloaded:
		return "unloaded"
	case PluginLoadEventReloaded:
		return "reloaded"
	case PluginLoadEventFailed:
		return "failed"
	default:
		return "unknown"
	}
}

// PluginLoadEventHandler 表示插件加载事件处理器
type PluginLoadEventHandler interface {
	// HandlePluginLoadEvent 处理插件加载事件
	HandlePluginLoadEvent(event PluginLoadEvent, plugin *PluginInfo, err error)
}

// PluginHotLoader 表示插件热加载器
type PluginHotLoader struct {
	// pluginsDir 是插件目录
	pluginsDir string
	// plugins 是插件映射表
	plugins map[string]*PluginInfo
	// requiredSymbols 是必需符号列表
	requiredSymbols []PluginSymbol
	// watcher 是文件系统监视器
	watcher *fsnotify.Watcher
	// handlers 是事件处理器列表
	handlers []PluginLoadEventHandler
	// mu 是互斥锁
	mu sync.RWMutex
	// running 是运行标志
	running bool
	// stopCh 是停止通道
	stopCh chan struct{}
	// wg 是等待组
	wg sync.WaitGroup
}

// NewPluginHotLoader 创建一个新的插件热加载器
func NewPluginHotLoader(pluginsDir string, requiredSymbols []PluginSymbol) (*PluginHotLoader, error) {
	// 创建文件系统监视器
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("failed to create watcher: %w", err)
	}

	return &PluginHotLoader{
		pluginsDir:      pluginsDir,
		plugins:         make(map[string]*PluginInfo),
		requiredSymbols: requiredSymbols,
		watcher:         watcher,
		handlers:        make([]PluginLoadEventHandler, 0),
		running:         false,
		stopCh:          make(chan struct{}),
	}, nil
}

// Start 启动插件热加载器
func (l *PluginHotLoader) Start() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if l.running {
		return errors.New("plugin hot loader is already running")
	}

	// 确保插件目录存在
	err := os.MkdirAll(l.pluginsDir, 0755)
	if err != nil {
		return fmt.Errorf("failed to create plugins directory: %w", err)
	}

	// 监视插件目录
	err = l.watcher.Add(l.pluginsDir)
	if err != nil {
		return fmt.Errorf("failed to watch plugins directory: %w", err)
	}

	// 加载现有插件
	err = l.loadExistingPlugins()
	if err != nil {
		return fmt.Errorf("failed to load existing plugins: %w", err)
	}

	// 启动监视循环
	l.running = true
	l.wg.Add(1)
	go l.watchLoop()

	return nil
}

// Stop 停止插件热加载器
func (l *PluginHotLoader) Stop() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	if !l.running {
		return errors.New("plugin hot loader is not running")
	}

	// 停止监视循环
	close(l.stopCh)
	l.wg.Wait()

	// 关闭监视器
	err := l.watcher.Close()
	if err != nil {
		return fmt.Errorf("failed to close watcher: %w", err)
	}

	// 卸载所有插件
	for id, plugin := range l.plugins {
		l.triggerEvent(PluginLoadEventUnloaded, plugin, nil)
		delete(l.plugins, id)
	}

	l.running = false
	return nil
}

// AddEventHandler 添加事件处理器
func (l *PluginHotLoader) AddEventHandler(handler PluginLoadEventHandler) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.handlers = append(l.handlers, handler)
}

// RemoveEventHandler 移除事件处理器
func (l *PluginHotLoader) RemoveEventHandler(handler PluginLoadEventHandler) bool {
	l.mu.Lock()
	defer l.mu.Unlock()

	for i, h := range l.handlers {
		if h == handler {
			l.handlers = append(l.handlers[:i], l.handlers[i+1:]...)
			return true
		}
	}
	return false
}

// GetPlugin 获取插件
func (l *PluginHotLoader) GetPlugin(id string) (*PluginInfo, bool) {
	l.mu.RLock()
	defer l.mu.RUnlock()
	plugin, ok := l.plugins[id]
	return plugin, ok
}

// GetAllPlugins 获取所有插件
func (l *PluginHotLoader) GetAllPlugins() []*PluginInfo {
	l.mu.RLock()
	defer l.mu.RUnlock()

	plugins := make([]*PluginInfo, 0, len(l.plugins))
	for _, plugin := range l.plugins {
		plugins = append(plugins, plugin)
	}
	return plugins
}

// LoadPlugin 加载插件
func (l *PluginHotLoader) LoadPlugin(path string) (*PluginInfo, error) {
	// 获取绝对路径
	absPath, err := filepath.Abs(path)
	if err != nil {
		return nil, fmt.Errorf("failed to get absolute path: %w", err)
	}

	// 检查文件是否存在
	_, err = os.Stat(absPath)
	if err != nil {
		return nil, fmt.Errorf("failed to stat plugin file: %w", err)
	}

	// 获取插件ID
	id := filepath.Base(absPath)

	// 加载插件
	handle, err := plugin.Open(absPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open plugin: %w", err)
	}

	// 创建插件信息
	pluginInfo := &PluginInfo{
		ID:       id,
		Path:     absPath,
		Symbols:  make(map[PluginSymbol]interface{}),
		LoadTime: time.Now(),
		Handle:   handle,
	}

	// 加载必需符号
	for _, symbol := range l.requiredSymbols {
		sym, err := handle.Lookup(string(symbol))
		if err != nil {
			return nil, fmt.Errorf("failed to lookup symbol %s: %w", symbol, err)
		}
		pluginInfo.Symbols[symbol] = sym
	}

	// 加载插件名称和版本
	if nameSymbol, err := handle.Lookup("Name"); err == nil {
		if name, ok := nameSymbol.(*string); ok {
			pluginInfo.Name = *name
		}
	}

	if versionSymbol, err := handle.Lookup("Version"); err == nil {
		if version, ok := versionSymbol.(*string); ok {
			pluginInfo.Version = *version
		}
	}

	// 存储插件信息
	l.mu.Lock()
	l.plugins[id] = pluginInfo
	l.mu.Unlock()

	// 触发事件
	l.triggerEvent(PluginLoadEventLoaded, pluginInfo, nil)

	return pluginInfo, nil
}

// UnloadPlugin 卸载插件
func (l *PluginHotLoader) UnloadPlugin(id string) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	// 检查插件是否存在
	plugin, ok := l.plugins[id]
	if !ok {
		return fmt.Errorf("plugin %s not found", id)
	}

	// 删除插件信息
	delete(l.plugins, id)

	// 触发事件
	l.triggerEvent(PluginLoadEventUnloaded, plugin, nil)

	return nil
}

// ReloadPlugin 重新加载插件
func (l *PluginHotLoader) ReloadPlugin(id string) (*PluginInfo, error) {
	l.mu.Lock()
	// 检查插件是否存在
	plugin, ok := l.plugins[id]
	if !ok {
		l.mu.Unlock()
		return nil, fmt.Errorf("plugin %s not found", id)
	}

	// 获取插件路径
	path := plugin.Path

	// 删除插件信息
	delete(l.plugins, id)
	l.mu.Unlock()

	// 触发卸载事件
	l.triggerEvent(PluginLoadEventUnloaded, plugin, nil)

	// 重新加载插件
	newPlugin, err := l.LoadPlugin(path)
	if err != nil {
		l.triggerEvent(PluginLoadEventFailed, plugin, err)
		return nil, fmt.Errorf("failed to reload plugin: %w", err)
	}

	// 触发重新加载事件
	l.triggerEvent(PluginLoadEventReloaded, newPlugin, nil)

	return newPlugin, nil
}

// loadExistingPlugins 加载现有插件
func (l *PluginHotLoader) loadExistingPlugins() error {
	// 读取插件目录
	entries, err := os.ReadDir(l.pluginsDir)
	if err != nil {
		return fmt.Errorf("failed to read plugins directory: %w", err)
	}

	// 加载所有插件
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		// 检查文件扩展名
		if filepath.Ext(entry.Name()) != ".so" {
			continue
		}

		// 加载插件
		path := filepath.Join(l.pluginsDir, entry.Name())
		_, err := l.LoadPlugin(path)
		if err != nil {
			// 记录错误但继续加载其他插件
			fmt.Printf("Failed to load plugin %s: %v\n", path, err)
		}
	}

	return nil
}

// watchLoop 监视循环
func (l *PluginHotLoader) watchLoop() {
	defer l.wg.Done()

	for {
		select {
		case <-l.stopCh:
			return
		case event, ok := <-l.watcher.Events:
			if !ok {
				return
			}
			l.handleWatchEvent(event)
		case err, ok := <-l.watcher.Errors:
			if !ok {
				return
			}
			fmt.Printf("Watcher error: %v\n", err)
		}
	}
}

// handleWatchEvent 处理监视事件
func (l *PluginHotLoader) handleWatchEvent(event fsnotify.Event) {
	// 检查文件扩展名
	if filepath.Ext(event.Name) != ".so" {
		return
	}

	// 获取插件ID
	id := filepath.Base(event.Name)

	// 处理事件
	switch {
	case event.Op&fsnotify.Create == fsnotify.Create:
		// 新插件创建
		_, err := l.LoadPlugin(event.Name)
		if err != nil {
			fmt.Printf("Failed to load new plugin %s: %v\n", event.Name, err)
		}
	case event.Op&fsnotify.Write == fsnotify.Write:
		// 插件更新
		l.mu.RLock()
		_, exists := l.plugins[id]
		l.mu.RUnlock()

		if exists {
			_, err := l.ReloadPlugin(id)
			if err != nil {
				fmt.Printf("Failed to reload plugin %s: %v\n", event.Name, err)
			}
		}
	case event.Op&fsnotify.Remove == fsnotify.Remove:
		// 插件删除
		l.mu.RLock()
		plugin, exists := l.plugins[id]
		l.mu.RUnlock()

		if exists {
			l.mu.Lock()
			delete(l.plugins, id)
			l.mu.Unlock()
			l.triggerEvent(PluginLoadEventUnloaded, plugin, nil)
		}
	}
}

// triggerEvent 触发事件
func (l *PluginHotLoader) triggerEvent(event PluginLoadEvent, plugin *PluginInfo, err error) {
	l.mu.RLock()
	handlers := make([]PluginLoadEventHandler, len(l.handlers))
	copy(handlers, l.handlers)
	l.mu.RUnlock()

	for _, handler := range handlers {
		handler.HandlePluginLoadEvent(event, plugin, err)
	}
}

// CopyPlugin 复制插件文件
func CopyPlugin(src, dst string) error {
	// 打开源文件
	srcFile, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("failed to open source file: %w", err)
	}
	defer srcFile.Close()

	// 创建目标文件
	dstFile, err := os.Create(dst)
	if err != nil {
		return fmt.Errorf("failed to create destination file: %w", err)
	}
	defer dstFile.Close()

	// 复制文件内容
	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return fmt.Errorf("failed to copy file content: %w", err)
	}

	// 同步文件
	err = dstFile.Sync()
	if err != nil {
		return fmt.Errorf("failed to sync file: %w", err)
	}

	return nil
}
